namespace tools {

	export const RequestType = {
		JSON: "application/json",
		FORM_URL: "application/x-www-form-urlencoded",
		TEXT: "text/plain",
		FORM_DATA: "multipart/form-data",
	}

	export type THttpNext = {
		completeHandler?: (response: any) => any,
		failHandler?: (type: string, data?: any) => any,
		progressHandler?: (loaded: number, total: number) => any,
		context?: any,
		withCover?: boolean,
		requestType?: string,
		responseType?: string,
	}

	export class Http {

		private $url: string;		//url(url存在时直接使用，否则用主机+端口)
		private $host: string;		//主机
		private $port: number;		//端口
		private $header: any;		//请求头
		private $params: any;		//Get参数
		private $data: any;			//Post数据
		private $route: string;		//路由
		private $next: THttpNext;	//请求处理
		private static $LOCAL_HOST: string = 'localhost';

		//Singleton
		private static $instance: Http;
		private constructor() { }
		public static get instance(): Http {
			if (!this.$instance) this.$instance = new Http()._clear();
			return this.$instance;
		}

		private _clear(): Http {
			this.$url = '';
			this.$host = '';
			this.$port = null;
			this.$header = {};
			this.$params = {};
			this.$data = {};
			this.$route = '';
			this.$next = null;
			tools.cover.hide();
			return this;
		}

		public setHost(host: string): Http {
			this.$host = host;
			return this;
		}

		public setPort(port: number): Http {
			this.$port = port;
			return this;
		}

		public setRoute(route: string): Http {
			this.$route = route;
			return this;
		}

		public setUrl(url: string): Http {
			this.$url = url;
			return this;
		}

		public addParam(key: string, value: any): Http {
			if (key) this.$params[key] = value;
			return this;
		}

		public addHeader(key: string, value: any): Http {
			if (key && value) this.$header[key] = value;
			return this;
		}

		public setData(data: any): Http {
			this.$data = data;
			return this;
		}

		public toGet(next: THttpNext): void {
			this.$next = next;
			let req: egret.HttpRequest = this._prepare;
			req.open(this._url + this._params, egret.HttpMethod.GET);
			req.send();
		}

		public toPost(next: THttpNext): void {
			this.$next = next;
			if (!next.requestType) this.$next.requestType = RequestType.JSON;
			let req: egret.HttpRequest = this._prepare;
			req.open(this._url, egret.HttpMethod.POST);
			req.send(JSON.stringify(this.$data));
		}

		private get _prepare(): egret.HttpRequest {
			let req = new egret.HttpRequest();
			//设置请求数据类型
			if (this.$next.requestType) req.setRequestHeader("Content-Type", this.$next.requestType);
			//设置返回数据类型
			req.responseType = this.$next.responseType ? this.$next.responseType : egret.HttpResponseType.TEXT;
			//设置通信阻挡面板
			this.$next.withCover ? tools.cover.show() : tools.cover.hide();
			//设置请求头
			for (let key in this.$header) {
				req.setRequestHeader(key, this.$header[key]);
			}
			//设置handler
			req.addEventListener(egret.IOErrorEvent.IO_ERROR, this._onError, this);
			req.addEventListener(egret.ProgressEvent.PROGRESS, this._onProgress, this);
			req.addEventListener(egret.Event.COMPLETE, this._onCompleted, this);
			return req;
		}

		private get _url(): string {
			let [url, iph] = ['', null];
			// game.initParams.http]; todo 
			if (this.$host) url = `${this.$host}${this.$port ? ':' + this.$port : ''}`;
			else if (this.$url) url = this.$url;
			else if (iph && iph.local) url = `${Http.$LOCAL_HOST}${iph.port ? ':' + iph.port : ''}`;
			else if (iph && iph.host) url = `${iph.host}${iph.port ? ':' + iph.port : ''}`;
			if (!url.startsWith('http')) url = 'http://' + url;
			return `${url}/${this.$route}?`;
		}

		private get _params(): string {
			let arr = [];
			for (let key in this.$params) {
				arr.push(`${key}=${this.$params[key]}`);
			}
			return arr.join('&');
		}

		private _onError(event: egret.IOErrorEvent): void {
			if (isFunc(this.$next.failHandler)) {
				if (this.$next.context) Reflect.apply(this.$next.failHandler, this.$next.context, [event.type, event.data])
				else this.$next.failHandler(event.type, event.data);
			} else console.error("http request error : ", event.type, event.data);
			this._clear();
		}

		private _onProgress(event: egret.ProgressEvent): void {
			if (isFunc(this.$next.progressHandler)) {
				if (this.$next.context) Reflect.apply(this.$next.progressHandler, this.$next.context, [event.bytesLoaded, event.bytesTotal])
				else this.$next.progressHandler(event.bytesLoaded, event.bytesTotal);
			} else console.info("http request progress : " + Math.floor(100 * event.bytesLoaded / event.bytesTotal) + "%");
			if (event.bytesLoaded >= event.bytesTotal && !isFunc(this.$next.completeHandler)) this._clear();
		}

		private _onCompleted(event: egret.Event): void {
			let res = (<egret.HttpRequest>event.currentTarget).response;
			if (isFunc(this.$next.completeHandler)) {
				if (this.$next.context) Reflect.apply(this.$next.completeHandler, this.$next.context, [res])
				else this.$next.completeHandler(res);
			} else console.info("http request onCompleted with no handler...");
			this._clear();
		}

		// public addSign(uid: string, token: string): Http {
		// 	// if (!token) {
		// 	// 	token = "";
		// 	// } else {
		// 	// 	this.addHeader("token", token);
		// 	// }
		// 	// if (uid) {
		// 	// 	this.addHeader("uid", uid);
		// 	// }
		// 	// var time = new Date().getTime();
		// 	// var sign = new md5().hex_md5(`${token}${time}${WXConfig.SignKey}`);
		// 	// this.addHeader("time", `${time}`);
		// 	// this.addHeader("sign", sign);
		// 	return this;
		// }
	}
}